home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Visual Database / Visual Foxpro 6.0 (Ent. Edition) / Vf6ent Extractor.EXE / TOOLS / XSOURCE / XSOURCE.ZIP / vfpsource / wizards / Wzcommon / wzengine.prg < prev   
Encoding:
Text File  |  1998-05-01  |  53.6 KB  |  1,946 lines

  1. #include "wizard.h"
  2.  
  3. #DEFINE MAC_BUILD 0
  4.  
  5. EXTERNAL ARRAY aSortArray
  6.  
  7. **************************************************************************
  8. **************************************************************************
  9. * Summary of Classes:
  10. *
  11. *    WizEngine - base Wizard Engine
  12. *
  13. *        ReadSettings - reads preference settings
  14. *        WriteSettings - writes preference settings
  15. *        Error - common error handling
  16. *        ErrorCleanup - stub method for use with specific wizard called by Error
  17. *        Alert - displays MessageBox alert
  18. *        ProcessOutput - stub for specific wizard to process output
  19. *        AddTherm - use to get a thermometer
  20. *        AddHandleToCloseList - adds a LLFF handle to list to be closed during destroy
  21. *        AddAliasToPreservedList    - adds alias to list of aliases to preserve during destroy
  22. *        CloseUnpreservedAliases - close all aliases that aren't on the preserved list
  23. *        CloseHandles - close all handles that are on the close list
  24. *        GetOS - returns operating system code (see #DEFINES)
  25. *
  26. *-  These are used by VFP for the Macintosh if MAC_BUILD is # 0
  27. *-
  28. *-      SetLibrary        -- open an API library
  29. *-        LocateApp        -- returns path to app of a given signature
  30. *-        PutPref            -- write a value to an INI-style file
  31. *-        GetPref            -- retrieve a value from an INI-style file
  32. *-        FindINI            -- search for a file (really, any file)
  33. *-        GetINISection    -- populate an array with all items within a given INI file section
  34. *-        FxStripLF        -- strip linefeeds from a file
  35. *
  36. *
  37. *    WizEngineAll - subclass of WizEngine. Has common methods to use
  38. *    
  39. *        AScanner - does ASCAN on column of array
  40. *        AColScan - does ASCAN on column of array
  41. *        InsaItem - insert item into array
  42. *        DelaItem - delete item from array
  43. *        SaveOutFile - asks for output file name and checks if it can be used
  44. *        JustPath - returns path of file name
  45. *        JustStem - returns stem of file name (name only with no extension)
  46. *        JustFName - returns file name
  47. *        ForceExt - forces file to have certain extension
  48. *        AddBs - adds backslash (colon for Macs) to file path if needed
  49. *        GetStyle - returns a FoxPro font style code based on Bold, Italic, Underline, etc. 
  50. *        AddCdxTag - adds a tag to CDX index 
  51. *        GetTagExpr - used by AddCdxTag to get tag expression for specific data types
  52. *        GetDBCAlias - returns DBC alias
  53. *        GetFullTagExpr - returns full tag expression for sort array
  54. *        CheckDBCTag - tests if DBC is opened non-exclusive so tag cannot be made 
  55. **************************************************************************
  56. **************************************************************************
  57.  
  58. ******************************************************************************
  59. * Used by GetOS and other methods
  60. ******************************************************************************
  61. * Operating System codes
  62. #DEFINE    OS_W32S                1
  63. #DEFINE    OS_NT                2
  64. #DEFINE    OS_WIN95            3
  65. #DEFINE    OS_MAC                4
  66. #DEFINE    OS_DOS                5
  67. #DEFINE    OS_UNIX                6
  68.  
  69. ******************************************************************************
  70. * Used by AddCdxTag/GetTagExpr method
  71. ******************************************************************************
  72.  
  73. * Data types
  74. #DEFINE DT_INTEGER     'I'
  75. #DEFINE DT_NUM       'N'
  76. #DEFINE DT_FLOAT     'F'
  77. #DEFINE DT_LOGIC     'L'
  78. #IFNDEF DT_MEMO
  79.     #DEFINE DT_MEMO  'M'
  80. #ENDIF
  81. #DEFINE DT_GEN       'G'
  82. #DEFINE DT_CHAR      'C'
  83. #DEFINE DT_DATE      'D'
  84. #DEFINE DT_DATETIME    'T'
  85. #DEFINE DT_CURRENCY    'Y'
  86. #DEFINE DT_DOUBLE    'B'
  87. #DEFINE C_FILEUSE_LOC    "File in use. Could not create index."
  88. #DEFINE C_BADPARMS_LOC    "Incorrect number of parameters passed to indexing routine."
  89. #DEFINE C_EXCLUSIVE_LOC    "EXCLUSIVE"
  90.  
  91. ******************************************************************************
  92. * Used by SaveOutFile method
  93. ******************************************************************************
  94. #DEFINE C_FILEUSE2_LOC        "File is in use. Please select another."
  95.  
  96. ******************************************************************************
  97. * Used by Error method
  98. ******************************************************************************
  99. #define ERRORTITLE_LOC        "Microsoft Visual FoxPro Wizards"
  100. #define NORUNTIME_LOC ;
  101.     "Microsoft Visual FoxPro Wizards require the Standard or Professional version."
  102.     
  103. #define ERRORMESSAGE_LOC ;
  104.     "Error #" + alltrim(str(m.nError)) + " in " + m.cMethod + ;
  105.     " (" + alltrim(str(m.nLine)) + "): " + m.cMessage
  106.  
  107. * The result of the above message will look like this:
  108. *
  109. *        Error #1 in WIZTEMPLATE.INIT (14): File does not exist.
  110.  
  111. #define MB_ICONEXCLAMATION        48
  112. #define MB_ABORTRETRYIGNORE        2
  113. #define MB_OK                    0
  114.  
  115. ******************************************************************************
  116. * Used by Alert method
  117. ******************************************************************************
  118. #define ALERTTITLE_LOC        "Microsoft Visual FoxPro Wizards"
  119.         
  120. ******************************************************************************
  121. * Used by ProcessOutput method
  122. ******************************************************************************
  123. #define NOPROCESS_LOC        "No process defined."
  124.  
  125.  
  126. ******************************************************************************
  127. DEFINE CLASS WizEngine AS custom
  128. ******************************************************************************
  129. *!*        name = "wzengine"    && this change broke object references in several wizards
  130.  
  131.     * Wizard Globals
  132.     iHelpContextID = 0        && used as default
  133.     cWizName = ""            && wizard name    (e.g., Group/Total report)
  134.     cWizClass = ""            && wizard class    (e.g., Report)
  135.     nTimeStamp = 0            && time stamp
  136.     cWizVersion = "6.0"        && version number
  137.     cVisFoxVersion = PADR(VAL(SUBSTR(VERSION(),ATC("FOXPRO",VERSION()) + 7)),1)    && version number (e.g., '5')
  138.     cWizTitle = ""            && output document title
  139.     cOutFile = ""            && output file name
  140.     cDBCName = ""            && DBC name
  141.     cDBCAlias = ""            && DBC Alias name
  142.     cDBCTable = ""            && DBC Table name
  143.     nWizWorkArea = 0        && table workarea
  144.     cWizAlias = ""            && table alias
  145.     nWizAction = 1            && output action    (e.g., Save and modify)
  146.     cWizOptions = ""        && wizard options (e.g., NOSCRN)
  147.     lSortAscend = .T.        && sort tag
  148.     lHasSortTag = .F.        && uses index tag
  149.     SetErrorOff = .F.        && bypass normal Error handling
  150.     HadError = .f.            && error occurred
  151.     iError = -1                && error number
  152.     cMessage = ''            && error message
  153.     lCancelled = .F.        && was the wizard cancelled?
  154.     
  155.     lHasNoTask = .f.        && whether wizard should perform output task
  156.     ThermRef = ""            && reference to thermometer
  157.     lInitValue = .t.        && used to prevent instantiation of the wizard
  158.                             && don't modify directly--return desired value from Init2
  159.     nCurrentOS = 0            && operating system code
  160.     lForceExclusive = .T.    && force SET EXCLUSIVE ON (needed for DBC operations)
  161.     
  162.     * This member is passed to Init by WizardTemplate when the oEngine object is 
  163.     * created. The member contains the name of the procedure to RETURN TO
  164.     * when an error occurs in the engine. Typical settings would be
  165.     * WIZARD (return to Wizard.app) or MASTER (return to Command window).
  166.     cReturnToProc = ''
  167.                            
  168.     DIMENSION aSettings[1,2]    && array of settings to save as prefs
  169.     aSettings = ""            
  170.     DIMENSION aDBFList[1]        && array of tables for table picker
  171.     aDBFList = ""
  172.     DIMENSION aWizTables[1,1]    && array of tables used
  173.     aWizTables = ""
  174.     DIMENSION aWizFields[1,1]    && array of selected fields
  175.     aWizFields = ""
  176.     DIMENSION aWizFList[1,1]    && array of all fields (nx7 -- AFIELDS)
  177.     aWizFList = ""
  178.     DIMENSION aWizLabels[1,1]    && array of selected english field labels
  179.     aWizLabels = ""
  180.     DIMENSION aWizSorts[1,1]    && array of sort fields
  181.     aWizSorts = ""
  182.     DIMENSION aCalcFields[1,1]    && array of Calculated fields
  183.     aCalcFields = ""
  184.     
  185.     * This array is used to store the list of aliases at startup. During Destroy,
  186.     * if an alias is not in this array, it is closed.
  187.     dimension aAliasesToPreserve[1, 2]
  188.     
  189.     * This array is used to store a list of LLFF handles to be closed during Destroy.
  190.     dimension aHandlesToClose[1]
  191.     aHandlesToClose = -1
  192.     
  193.     * This array is used to store a list of libraries to be released during Destroy.
  194.     dimension aReleaseLibraryList[1]
  195.     aReleaseLibraryList = ''
  196.     
  197.     * This array is used to store environment settings saved during Setup (called by Init)
  198.     * and restored in Cleanup (called by Destroy).
  199.     dimension aEnvironment[1]
  200.     
  201.     procedure AddHandleToCloseList
  202.         * This procedure is used to add a LLFF handle to the this.aHandlesToClose list.
  203.         * These handles are closed during Destroy.
  204.         parameters iHandle
  205.         if ascan(this.aHandlesToClose, m.iHandle) = 0
  206.             if this.aHandlesToClose[1] <> -1
  207.                 dimension this.aHandlesToClose[alen(this.aHandlesToClose) + 1]
  208.             endif
  209.             this.aHandlesToClose[alen(this.aHandlesToClose)] = m.iHandle
  210.         endif
  211.     endproc
  212.  
  213.     procedure AddAliasToPreservedList
  214.         * This procedure is used to add an alias to the this.aAliasesToPreserve list.
  215.         * These aliases are left open during Destroy.
  216.         parameters cAlias
  217.         local cExact, i
  218.         m.cExact = set('exact')
  219.         set exact on
  220.         if ascan(this.aAliasesToPreserve, upper(m.cAlias)) = 0
  221.             m.i = alen(this.aAliasesToPreserve, 1)
  222.             if .not. empty(this.aAliasesToPreserve[1, 1])
  223.                 m.i = m.i + 1
  224.                 dimension this.aAliasesToPreserve[m.i, alen(this.aAliasesToPreserve, 2)]
  225.             endif
  226.             this.aAliasesToPreserve[m.i, 1] = upper(m.cAlias)
  227.             this.aAliasesToPreserve[m.i, 2] = select(upper(m.cAlias))
  228.         endif
  229.     endproc
  230.     
  231.     procedure CloseUnpreservedAliases
  232.         * This procedure closes aliases which were not open during Init
  233.         * (i.e. are not found in this.aAliasesToPreserve)
  234.  
  235.         local i, cExact
  236.         local array aAliasesInUse[1, 2]
  237.         
  238.         if .not. empty(aused(aAliasesInUse))
  239.             m.cExact = set('exact')
  240.             set exact on
  241.             for m.i = 1 to alen(aAliasesInUse, 1)
  242.                 if ascan(this.aAliasesToPreserve, aAliasesInUse[m.i, 1]) = 0
  243.                     use in (aAliasesInUse[m.i, 1])
  244.                 endif
  245.             endfor
  246.             set exact &cExact
  247.         endif
  248.     endproc
  249.  
  250.     procedure CloseHandles
  251.         * This procedure closes low-level file handles store in this.aHandlesToClose
  252.  
  253.         local i
  254.  
  255.         if this.aHandlesToClose[1] <> -1
  256.             for m.i = 1 to alen(this.aHandlesToClose)
  257.                 =fclose(this.aHandlesToClose[m.i])
  258.             endfor
  259.         endif
  260.     endproc
  261.     
  262.     procedure AddLibraryToReleaseList
  263.         parameters cLibrary
  264.         if empty(ascan(this.aReleaseLibraryList, m.cLibrary))
  265.             if .not. empty(this.aReleaseLibraryList[1])
  266.                 dimension this.aReleaseLibraryList[alen(this.aReleaseLibraryList) + 1]
  267.             endif
  268.             this.aReleaseLibraryList[alen(this.aReleaseLibraryList)] = m.cLibrary
  269.         endif
  270.     endproc
  271.     
  272.     procedure ReleaseLibraries
  273.         * This procedure releases the libraries listed in aReleaseLibraryList[]
  274.         local i
  275.         for m.i = 1 to alen(this.aReleaseLibraryList)
  276.             if not empty(this.aReleaseLibraryList[m.i]) .and. ;
  277.                 upper(this.aReleaseLibraryList[m.i]) $ upper(set('library'))
  278.                 release library (this.aReleaseLibraryList[m.i])
  279.             endif
  280.         endfor
  281.     endproc
  282.     
  283.     procedure Destroy
  284.         this.Cleanup
  285.     endproc
  286.     
  287.     procedure Init
  288.         * cReturnToProc is the procedure to return to 
  289.         * if an error occurs in the engine. cProcedure is the
  290.         * SET('PROCEDURE') setting to restore in cleanup.
  291.         parameters cReturnToProc, cProcedure
  292.         
  293.         dimension this.aEnvironment[35,1]
  294.         this.aEnvironment[11,1] = 0
  295.  
  296.         IF .not. C_DEBUG
  297.             IF WEXIST("Visual Foxpro Debugger")
  298.                 HIDE WINDOW "Visual FoxPro Debugger"
  299.             ELSE
  300.                 * Using FoxPro frame
  301.                 IF WVISIBLE("Watch")
  302.                     this.aEnvironment[11,1] = 2^0
  303.                     RELEASE WINDOW Watch
  304.                 ENDIF
  305.                 IF WVISIBLE("Locals")
  306.                     this.aEnvironment[11,1] = this.aEnvironment[11,1] + 2^1                
  307.                     RELEASE WINDOW Locals
  308.                 ENDIF
  309.                 IF WVISIBLE("Call Stack")
  310.                     this.aEnvironment[11,1] = this.aEnvironment[11,1] + 2^2
  311.                     RELEASE WINDOW Call Stack
  312.                 ENDIF
  313.                 IF WVISIBLE("Debug Output")
  314.                     this.aEnvironment[11,1] = this.aEnvironment[11,1] + 2^3    
  315.                     RELEASE WINDOW debug output
  316.                 ENDIF                        
  317.                 IF WVISIBLE("Trace")
  318.                     this.aEnvironment[11,1] = this.aEnvironment[11,1] + 2^4
  319.                     RELEASE WINDOW trace
  320.                 ENDIF                        
  321.             ENDIF
  322.         ENDIF
  323.         
  324.         if used('THIS') .or. used('THISFORM') .or. used('THISFORMSET') ;
  325.             .or. used('OWIZARD') .or. used('OENGINE')
  326.             clear typeahead
  327.             if MessageBox(C_BADALIAS_LOC, MB_YESNO, ALERTTITLE_LOC) = IDYES
  328.                 * close the file and continue
  329.                 if used('this')
  330.                     use in this
  331.                 endif
  332.                 if used('thisform')
  333.                     use in thisform
  334.                 endif
  335.                 if used('thisformset')
  336.                     use in thisformset
  337.                 endif
  338.                 if used('owizard')
  339.                     use in owizard
  340.                 endif
  341.                 if used('oengine')
  342.                     use in oengine
  343.                 endif
  344.             else
  345.                 return .f.
  346.             endif
  347.         endif
  348.         
  349.         this.cReturnToProc = iif(!empty(m.cReturnToProc), m.cReturnToProc, '')
  350.  
  351.         this.Setup(m.cProcedure)
  352.         
  353.         this.lInitValue = this.Init2()
  354.  
  355.         if .not. this.lInitValue
  356.             this.Cleanup
  357.             return .f.
  358.             if empty(this.cReturnToProc)
  359.                 return .f.
  360.             endif
  361.         endif
  362.     endproc
  363.     
  364.     procedure Init2
  365.         * This is a stub for the Init2 method which may be created in
  366.         * subclass engines. The subclass engine may RETURN .F. to prevent
  367.         * the instantiation of the class.
  368.     endproc
  369.     
  370.     procedure Setup
  371.         parameters cProcedure
  372.         clear program
  373.         
  374.         this.aEnvironment[1,1] = SET("TALK")        
  375.         SET TALK OFF
  376.         
  377.         if parameters() = 0
  378.             m.cProcedure = set('procedure')
  379.         else
  380.             m.cProcedure = iif(empty(m.cProcedure), '', m.cProcedure)
  381.         endif
  382.         
  383.         this.aEnvironment[6,1] = set("exclusive")
  384.         IF this.lForceExclusive
  385.             set exclusive on
  386.         ENDIF
  387.  
  388.         this.aEnvironment[2,1] =  set("step")
  389.         this.aEnvironment[32,1] = on('escape')
  390.         this.aEnvironment[18,1] = set('escape')
  391.         push key clear
  392.         
  393.         this.aEnvironment[10,1] = set("trbetween")
  394.         
  395.         if .not. C_DEBUG
  396.             set step off
  397.             on escape
  398.             set escape off
  399.             set skip of bar _mpr_suspend of _mprog .T.
  400.             set skip of popup _mtools .T.
  401.             set trbetween off
  402.         endif
  403.                 
  404.         =aused(this.aAliasesToPreserve)
  405.         this.aEnvironment[5,1] = select()
  406.  
  407.         this.aEnvironment[3,1] = set("compatible")
  408.         set compatible off noprompt
  409.         this.aEnvironment[4,1] = m.cProcedure
  410.         this.aEnvironment[7,1] = set("message", 1)
  411.         set message to MESSAGE_LOC
  412.         this.aEnvironment[8,1] = set("safety")
  413.         set safety off
  414.         this.aEnvironment[9,1] = set("path")
  415.         this.aEnvironment[12,1] = set("fields")
  416.         set fields off
  417.         this.aEnvironment[13,1] = set("fields", 2)
  418.         set fields local
  419.         this.aEnvironment[14,1] = on("error")
  420.  
  421.         *- NOTE: oEngine.aEnvironment[17,1] is updated by main wizard program        
  422.         this.aEnvironment[17,1] = set("classlib")
  423.         
  424.         this.aEnvironment[19,1] = set("exact")
  425.         set exact on
  426.         this.aEnvironment[20,1] = set("echo")
  427.         set echo off
  428.         this.aEnvironment[21,1] = set("memowidth")
  429.         this.aEnvironment[22,1] = set("udfparms")
  430.         set udfparms to value
  431.         this.aEnvironment[23,1] = set("near")
  432.         set near off
  433.         this.aEnvironment[24,1] = set("unique")
  434.         set unique off
  435.         this.aEnvironment[25,1] = set("ansi")
  436.         set ansi off
  437.         this.aEnvironment[26,1] = set("carry")
  438.         set carry off
  439.         this.aEnvironment[27,1] = set("cpdialog")
  440.         set cpdialog off
  441.         this.aEnvironment[28,1] = set("status bar")
  442.         this.aEnvironment[29,1] = sys(5) + curdir()
  443.         this.aEnvironment[30,1] = set("deleted")
  444.         this.aEnvironment[31,1] = set("date")
  445.         this.aEnvironment[15,1] = set('point')
  446.         this.aEnvironment[33,1] = SET("database")
  447.  
  448.         IF _mac
  449.             this.aEnvironment[34,1] = SET('LIBRARY')
  450.         ENDIF
  451.  
  452.         *- always SET MULTILOCKS ON (to handle offline views)
  453.         THIS.aEnvironment[35,1] = SET("MULTILOCKS")
  454.         SET MULTILOCKS ON
  455.  
  456.         on key label f1 oEngine.Help
  457.     endproc
  458.     
  459.     procedure Cleanup
  460.         local iIndex, cListItem, cListItemList, cListItemAlias
  461.         
  462.         * Reset these in case something breaks later
  463.         set skip of popup _mtools .F.
  464.         set skip of bar _mpr_suspend of _mprog .F.
  465.  
  466.         this.CloseHandles
  467.         this.CloseUnpreservedAliases
  468.         this.ReleaseLibraries
  469.         
  470.         * copy this.aEnvironment to local aEnvironment so we can macro substitute directly
  471.         local array aEnvironment[alen(this.aEnvironment,1), alen(this.aEnvironment,2)]
  472.         =acopy(this.aEnvironment, aEnvironment)
  473.         
  474.         on key label f1
  475.         on key
  476.                 
  477.         set compatible &aEnvironment[3,1]
  478.         set procedure to
  479.         if .not. empty(aEnvironment[4,1])
  480.             m.iIndex = 1
  481.             do while .t.
  482.                 m.cListItem = this.ParseList(aEnvironment[4, 1], m.iIndex)
  483.                 if empty(m.cListItem)
  484.                     exit
  485.                 endif
  486.                 set procedure to (m.cListItem) additive
  487.                 m.iIndex = m.iIndex + 1
  488.             enddo
  489.         endif
  490.         
  491.  
  492.         set exclusive &aEnvironment[6,1]
  493.         select (aEnvironment[5,1])
  494.  
  495.         set message to [&aEnvironment[7,1]]
  496.         set safety &aEnvironment[8,1]
  497.         
  498.         if .not. empty(aEnvironment[9,1])
  499.             set path to &aEnvironment[9, 1]
  500.         else
  501.             set path to
  502.         endif
  503.         
  504.         set fields &aEnvironment[12,1]
  505.         set fields &aEnvironment[13,1]
  506.         on error &aEnvironment[14,1]
  507.         
  508.         set classlib to
  509.         if .not. empty(aEnvironment[17,1])
  510.             THIS.SetErrorOff = .T.
  511.             m.iIndex = 1
  512.             do while .t.
  513.                 m.cListItem = this.ParseList(aEnvironment[17, 1], m.iIndex)
  514.                 if empty(m.cListItem)
  515.                     exit
  516.                 endif
  517.                 if ' ALIAS ' $ m.cListItem
  518.                     m.cListItemAlias = substr(m.cListItem, at('ALIAS ', m.cListItem))
  519.                     m.cListItem = alltrim(strtran(m.cListItem, m.cListItemAlias))
  520.                     * Check for long file names with surrounding quotes - new to VFP5
  521.                     IF !FILE(m.cListItem) AND FILE(EVAL(m.cListItem))
  522.                         m.cListItem = EVAL(m.cListItem)
  523.                     ENDIF
  524.                     m.cListItemAlias = alltrim(substr(m.cListItemAlias, 6))
  525.                     set classlib to (m.cListItem) alias (m.cListItemAlias) additive
  526.                 else
  527.                     * Check for long file names with surrounding quotes - new to VFP5
  528.                     IF !FILE(m.cListItem) AND FILE(EVAL(m.cListItem))
  529.                         m.cListItem = EVAL(m.cListItem)
  530.                     ENDIF
  531.                     set classlib to (m.cListItem) additive
  532.                 endif
  533.                 m.iIndex = m.iIndex + 1
  534.             enddo
  535.             THIS.SetErrorOff = .F.
  536.         endif
  537.  
  538.         set exact &aEnvironment[19,1]
  539.         set memowidth to (aEnvironment[21,1])
  540.         set udfparms to &aEnvironment[22,1]
  541.         set near &aEnvironment[23,1]
  542.         set unique &aEnvironment[24,1]
  543.         set ansi &aEnvironment[25,1]
  544.         set carry &aEnvironment[26,1]
  545.         set cpdialog &aEnvironment[27,1]
  546.         set status bar &aEnvironment[28,1]
  547.         set default to (aEnvironment[29,1])
  548.         set deleted &aEnvironment[30,1]
  549.         set date to &aEnvironment[31,1]
  550.         set point to "&aEnvironment[15,1]"
  551.         set decimals to &aEnvironment[16,1]
  552.         
  553.         IF WEXIST("Visual Foxpro Debugger")
  554.         ELSE
  555.             IF BITAND(this.aEnvironment[11,1],2^0)#0
  556.                 ACTIVATE WINDOW Watch
  557.             ENDIF
  558.             IF BITAND(this.aEnvironment[11,1],2^1)#0
  559.                 ACTIVATE WINDOW Locals
  560.             ENDIF
  561.             IF BITAND(this.aEnvironment[11,1],2^2)#0
  562.                 ACTIVATE WINDOW "Call Stack"
  563.             ENDIF
  564.             IF BITAND(this.aEnvironment[11,1],2^3)#0
  565.                 ACTIVATE WINDOW "Debug Output"
  566.             ENDIF
  567.             IF BITAND(this.aEnvironment[11,1],2^4)#0
  568.                 ACTIVATE WINDOW "Trace"
  569.             ENDIF
  570.         ENDIF
  571.         
  572.         set trbetween &aEnvironment[10,1]
  573.         set talk &aEnvironment[1,1]
  574.         set step &aEnvironment[2,1]
  575.         set escape &aEnvironment[18,1]
  576.         on escape &aEnvironment[32,1]
  577.         this.SetErrorOff = .t.
  578.         set database to &aEnvironment[33,1]
  579.         this.SetErrorOff = .f.
  580.         this.haderror = .f. 
  581.  
  582.         IF _mac
  583.             IF NOT EMPTY(aEnvironment[34,1])
  584.                 SET LIBRARY TO (aEnvironment[34,1])
  585.             ELSE
  586.                 SET LIBRARY TO
  587.             ENDIF
  588.         ENDIF
  589.  
  590.         *- restore multilocks
  591.         * We need to trap for error and skip here because product allows
  592.         * a view to be opened with SET MULTI OFF, but once it is set ON
  593.         * you cannot reset it to OFF.
  594.         THIS.SetErrorOff = .T.
  595.         SET MULTILOCKS &aEnvironment[35,1]
  596.         THIS.SetErrorOff = .F.
  597.         pop key
  598.         
  599.     endproc
  600.     
  601.     procedure ParseList
  602.         parameters cList, iIndex
  603.         local cTemp
  604.         do case
  605.         case m.iIndex = 1
  606.             if occurs(',', m.cList) <> 0
  607.                 return alltrim(left(m.cList, at(',', m.cList) - 1))
  608.             else
  609.                 return alltrim(m.cList)
  610.             endif
  611.         case occurs(',', m.cList) < m.iIndex - 1
  612.             return ''
  613.         otherwise
  614.             m.cTemp = substr(m.cList, at(',', m.cList, m.iIndex - 1) + 1)
  615.             if occurs(',', m.cTemp) <> 0
  616.                 return alltrim(left(m.cTemp, at(',', m.cTemp) - 1))
  617.             else
  618.                 return alltrim(m.cTemp)
  619.             endif
  620.         endcase
  621.     endproc
  622.     
  623.     procedure ErrorCleanup
  624.         * This is a stub for subclasses which have cleanup to perform before
  625.         * the engine object is released in the Error method.
  626.     endproc
  627.     
  628.     PROCEDURE Error
  629.         Parameters nError, cMethod, nLine, oObject, cMessage
  630.  
  631.         local cAction
  632.         
  633.         THIS.HadError = .T.
  634.         this.iError = m.nError
  635.         this.cMessage = iif(empty(m.cMessage), message(), m.cMessage)
  636.         
  637.         if this.SetErrorOff
  638.             do case
  639.             case inlist(lower(THIS.cWizName), 'formwizard', 'mformwizard') ;
  640.                 AND ALLTRIM(STR(m.nError))$'3/108/1705/1708/1718'
  641.                  * Called if file opened with EXCLUSIVE OFF
  642.                 =THIS.ALERT(C_FILEUSE_LOC)
  643.               otherwise
  644.               endcase
  645.             RETURN
  646.         endif
  647.         
  648.         m.cMessage = iif(empty(m.cMessage), message(), m.cMessage)
  649.         if type('m.oObject') = 'O' .and. .not. isnull(m.oObject) .and. at('.', m.cMethod) = 0
  650.             m.cMethod = m.oObject.Name + '.' + m.cMethod
  651.         endif
  652.                 
  653.         if C_DEBUG
  654.             m.cAction = this.Alert(ERRORMESSAGE_LOC, MB_ICONEXCLAMATION + ;
  655.                 MB_ABORTRETRYIGNORE, ERRORTITLE_LOC)
  656.             do case
  657.             case m.cAction='RETRY'
  658.                 this.HadError = .f.
  659.                 clear typeahead
  660.                 set step on
  661.                 &cAction
  662.             case m.cAction='IGNORE'
  663.                 this.HadError = .f.
  664.                 return
  665.             endcase
  666.         else
  667.             if m.nError = 1098
  668.                 * User-defined error
  669.                 m.cAction = this.Alert(message(), MB_ICONEXCLAMATION + ;
  670.                     MB_OK, ERRORTITLE_LOC)
  671.             else
  672.                 m.cAction = this.Alert(ERRORMESSAGE_LOC, MB_ICONEXCLAMATION + ;
  673.                     MB_OK, ERRORTITLE_LOC)
  674.             endif
  675.         endif
  676.         this.ErrorCleanup
  677.         if !empty(this.cReturnToProc)
  678.             if type('oWizard.lEngineError') = 'L'
  679.                 oWizard.lEngineError = .t.
  680.             endif
  681.             release oWizard
  682.             release oEngine
  683.             local cReturnToProc
  684.             m.cReturnToProc = this.cReturnToProc
  685.             return to &cReturnToProc
  686.         else
  687.             release this
  688.         endif
  689.     ENDPROC
  690.     
  691.     PROCEDURE ReadSettings
  692.     ENDPROC
  693.  
  694.     PROCEDURE WriteSettings
  695.     ENDPROC
  696.  
  697.     PROCEDURE Alert
  698.         parameters m.cMessage, m.cOptions, m.cTitle, m.cParameter1, m.cParameter2
  699.  
  700.         private m.cOptions, m.cResponse
  701.  
  702.         m.cOptions = iif(empty(m.cOptions), 0, m.cOptions)
  703.  
  704.         if parameters() > 3 && a parameter was passed
  705.             m.cMessage = [&cMessage]
  706.         endif
  707.         
  708.         clear typeahead
  709.         if !empty(m.cTitle)
  710.             m.cResponse = MessageBox(m.cMessage, m.cOptions, m.cTitle)
  711.         else
  712.             m.cResponse = MessageBox(m.cMessage, m.cOptions, ALERTTITLE_LOC)
  713.         endif
  714.  
  715.         do case
  716.         * The strings below are used internally and should not 
  717.         * be localized
  718.         case m.cResponse = 1
  719.             m.cResponse = 'OK'
  720.         case m.cResponse = 6
  721.             m.cResponse = 'YES'
  722.         case m.cResponse = 7
  723.             m.cResponse = 'NO'
  724.         case m.cResponse = 2
  725.             m.cResponse = 'CANCEL'
  726.         case m.cResponse = 3
  727.             m.cResponse = 'ABORT'
  728.         case m.cResponse = 4
  729.             m.cResponse = 'RETRY'
  730.         case m.cResponse = 5
  731.             m.cResponse = 'IGNORE'
  732.         endcase
  733.         return m.cResponse
  734.  
  735.     ENDPROC
  736.  
  737.     PROCEDURE AddTherm
  738.         * If a modal formset exists, looks to see if there's a ThermRef member.
  739.         * If so, it's updated, otherwise a thermometer form is added to the 
  740.         * modal formset.
  741.         *
  742.         * If there is no modal formset (the engine is running standalone), 
  743.         * looks to see if there's a ThermRef member. If so, it's updated,
  744.         * otherwise a thermometer form is added to the engine.
  745.         *
  746.         * The parameters received are passed along to the Thermometer.Init
  747.         * or used to update the thermometer if it already exists.
  748.         *
  749.         * cTitle    Title displayed in thermometer
  750.         * iBasis    Basis used for calculating progress
  751.  
  752.         parameters cTitle, iBasis
  753.         
  754.         local i, orModalFormset
  755.  
  756.         set class to therm additive
  757.         m.orModalFormset = .NULL.
  758.         for m.i = 1 to _screen.FormCount
  759.             if type('_screen.Forms(m.i).Parent.BaseClass') = 'C' .and. ;
  760.                 lower(_screen.Forms(m.i).Parent.BaseClass) = 'formset' .and. ;
  761.                 _screen.Forms(m.i).Parent.WindowType = 1
  762.                 * There's a modal formset, probably (but not necessarily) WizTemplate
  763.                 
  764.                 m.orModalFormset = _screen.Forms(m.i).Parent
  765.                 exit
  766.             endif
  767.         endfor
  768.         
  769.         if .not. isnull(m.orModalFormset)
  770.             if type('m.orModalFormset.ThermRef') = 'O' .and. ;
  771.                 lower(m.orModalFormset.ThermRef.Class) = 'thermometer' .and. ;
  772.                 lower(m.orModalFormset.ThermRef.BaseClass) = 'form'
  773.  
  774.                 m.orModalFormset.ThermRef.lblTitle.Caption = ;
  775.                     iif(empty(m.cTitle), '', m.cTitle)
  776.                 m.orModalFormset.ThermRef.iBasis = iif(empty(m.iBasis), 0, m.iBasis)
  777.                 m.orModalFormset.ThermRef.Update(0, "") && reset to 0%, no task
  778.             else
  779.                 m.orModalFormset.AddObject("ThermRef", "Thermometer", m.cTitle, m.iBasis)
  780.             endif
  781.             THIS.ThermRef = m.orModalFormset.ThermRef
  782.             * Release the reference to the modal formset
  783.             m.orModalFormset = .NULL.
  784.         else
  785.             if type('this.ThermRef') = 'O' AND !ISNULL(this.ThermRef)
  786.                 this.ThermRef.lblTitle.Caption = ;
  787.                     iif(empty(m.cTitle), '', m.cTitle)
  788.                 this.ThermRef.iBasis = iif(empty(m.iBasis), 0, m.iBasis)
  789.                 this.ThermRef.Update(0, "") && reset to 0%, no task
  790.             else
  791.                 this.ThermRef = createobj("Thermometer", m.cTitle, m.iBasis)
  792.             endif
  793.         endif
  794.         if .not. C_DEBUG
  795.             this.ThermRef.AlwaysOnTop = .T.
  796.         else
  797.             this.ThermRef.AlwaysOnTop = .F.
  798.         endif
  799.     endproc
  800.     
  801.     procedure ProcessOutput
  802.         this.Alert(NOPROCESS_LOC)
  803.     endproc
  804.  
  805.     procedure Tick
  806.         public iTickTime
  807.         iTickTime = seconds()
  808.     endproc
  809.     
  810.     procedure Tock
  811.         parameters cDescription
  812.         local iSeconds
  813.         iSeconds = seconds()
  814.         activate screen
  815.         if !empty(m.cDescription)
  816.             ?m.cDescription + ': '
  817.         else
  818.             * No need to localize this -- it's used for debugging.
  819.             ?'Elapsed time: '
  820.         endif
  821.         ??str(((m.iSeconds - m.iTickTime) / 60), 5, 3)
  822.     endproc
  823.     
  824.     procedure Help
  825.         do case
  826.         case type('_screen.ActiveForm.cmdHelp') = 'O'
  827.             _screen.ActiveForm.cmdHelp.Click()
  828.         case type('_screen.ActiveForm') = 'O' .and. ;
  829.             type('_screen.ActiveForm.HelpContextID') = 'N' .and. ;
  830.             _screen.ActiveForm.HelpContextID <> 0
  831.             help id (_screen.ActiveForm.HelpContextID)
  832.         case this.iHelpContextID <> 0
  833.             help id (this.iHelpContextID)
  834.         otherwise
  835.             help
  836.         endcase
  837.     endproc        
  838.  
  839.     procedure GetOS
  840.         DO CASE
  841.         CASE _DOS 
  842.             THIS.nCurrentOS = OS_DOS
  843.         CASE _UNIX
  844.             THIS.nCurrentOS = OS_UNIX
  845.         CASE _MAC
  846.             THIS.nCurrentOS = OS_MAC
  847.         CASE ATC("Windows 3",OS(1)) # 0
  848.             THIS.nCurrentOS = OS_W32S
  849.         CASE ATC("Windows NT",OS(1)) # 0
  850.             THIS.nCurrentOS = OS_NT
  851.         OTHERWISE
  852.             * Some future system (Windows 95)
  853.             THIS.nCurrentOS = OS_WIN95
  854.         ENDCASE
  855.     endproc
  856.  
  857.     procedure addbs
  858.         parameters cString
  859.         return addbs(m.cString)
  860.     endproc
  861.     
  862.     procedure justpath
  863.         parameters cString
  864.         return justpath(m.cString)
  865.     endproc
  866.     
  867.     procedure justext
  868.         parameters cString
  869.         return justext(m.cString)
  870.     endproc
  871.     
  872.     procedure justfname
  873.         parameters cString
  874.         return justfname(m.cString)
  875.     endproc
  876.     
  877.     procedure WizLocFile
  878.         parameters cFilename, cPrompt
  879.         local cTempname, cWizardPath
  880.         local array aFile[1]
  881.         
  882.         * If we don't have access to JustFname, etc. (either in FoxTools or
  883.         * in WizEngineAll), just do a LOCFILE() the best we can and return.
  884.         this.HadError = .f.
  885.         this.SetErrorOff = .t.
  886.         m.cTempname = this.justfname(m.cFilename)
  887.         this.SetErrorOff = .f.
  888.         
  889.         if this.HadError
  890.             if type('m.cPrompt') <> 'C' .or. empty(m.cPrompt)
  891.                 m.cPrompt = proper(m.cFilename) + ':'
  892.             endif
  893.             this.HadError = .f.
  894.             this.SetErrorOff = .t.
  895.             m.cTempname = locfile(m.cFilename, '', m.cPrompt)
  896.             this.SetErrorOff = .f.
  897.             if this.HadError
  898.                 this.HadError = .f.
  899.                 m.cTempname = ''
  900.             endif
  901.             return m.cTempname
  902.         endif
  903.         
  904.         m.cTempname = this.justfname(m.cFilename)
  905.         if adir(aFile, sys(2004) + m.cTempname) = 1
  906.             m.cTempname = sys(2004) + m.cTempname
  907.         else
  908.             IF EMPTY(_wizard)
  909.                 m.cWizardpath = sys(2004)
  910.             ELSE
  911.                 m.cWizardPath = this.addbs(this.justpath(_wizard))
  912.             ENDIF
  913.             do case
  914.             case adir(aFile, m.cWizardPath + m.cTempname) = 1
  915.                 m.cTempname = m.cWizardPath + m.cTempname
  916.             case adir(aFile, m.cWizardPath + "WIZARDS\" + m.cTempname) = 1
  917.                 m.cTempname = m.cWizardPath + "WIZARDS\" + m.cTempname
  918.             otherwise
  919.                 if type('m.cPrompt') <> 'C' .or. empty(m.cPrompt)
  920.                     m.cPrompt = proper(m.cTempname) + ':'
  921.                 endif
  922.                 this.HadError = .f.
  923.                 this.SetErrorOff = .t.
  924.                 m.cTempname = locfile(m.cTempname, this.justext(m.cTempname), m.cPrompt)
  925.                 this.SetErrorOff = .f.
  926.                 if this.HadError
  927.                     this.HadError = .f.
  928.                     m.cTempname = ''
  929.                 else
  930.                     if adir(aFile, m.cTempname) = 0
  931.                         this.Alert(E_FILENOTFOUND_LOC)
  932.                         m.cTempname = ''
  933.                     endif
  934.                 endif
  935.             endcase
  936.         endif
  937.         return m.cTempname
  938.     endproc
  939.  
  940. #IF MAC_BUILD
  941.  
  942. * These functions are for Mac only
  943.  
  944.     *----------------------------------
  945.     FUNCTION GetMacCPU
  946.     *----------------------------------
  947.         RETURN IIF(C_MACPPC_TAG_LOC $ UPPER(VERS()),"PPC","68K")
  948.     ENDFUNC
  949.  
  950.     *----------------------------------
  951.     FUNCTION SetLibrary
  952.     *----------------------------------
  953.         *- a function to set FoxTools
  954.         *- returns path + name of library, or empty string if failure
  955.  
  956.         PARAMETER cLibraryFName, cSpecialDir, cVersionFuncName, cReqVersion, cBadVersMessage, cBadLibMessage
  957.         LOCAL cLibrary
  958.  
  959.         cLibrary = ""
  960.  
  961.         IF !_mac
  962.             *- this is a Mac only function
  963.             RETURN ""
  964.         ENDIF
  965.  
  966.         DO CASE
  967.             CASE cLibraryFName $ SET('library')
  968.                 IF PARAMETERS() > 2
  969.                     IF &cVersionFuncName() < cReqVersion
  970.                         THIS.Alert(cBadVersMessage + cLibraryFName)
  971.                         RETURN ""
  972.                     ENDIF
  973.                 ENDIF
  974.                 cLibrary = cLibraryFName
  975.                 
  976.             CASE !EMPTY(cSpecialDir) AND ADIR(aFile, THIS.AddBS(cSpecialDir) + cLibraryFName) = 1
  977.                 *- look in requested folder first
  978.                 THIS.SetErrorOff = .t.
  979.                 cLibrary = THIS.AddBS(cSpecialDir) + cLibraryFName
  980.                 SET LIBRARY TO (THIS.AddBS(cSpecialDir) + cLibraryFName) ADDITIVE
  981.                 THIS.SetErrorOff = .f.
  982.                 IF THIS.HadError
  983.                     THIS.Alert(cBadLibMessage + ".")
  984.                     RETURN ""
  985.                 ENDIF
  986.                 IF PARAMETERS() > 2
  987.                     IF &cVersionFuncName() < cReqVersion
  988.                         RELEASE LIBRARY (cLibrary)
  989.                         THIS.Alert(cBadVersMessage + cLibraryFName)
  990.                         RETURN ""
  991.                     ENDIF
  992.                 ENDIF
  993.                 
  994.             CASE ADIR(aFile, SYS(2033,1) + ":" + cLibraryFName) = 1
  995.                 *- look in extensions folder
  996.                 THIS.SetErrorOff = .t.
  997.                 cLibrary = SYS(2033,1) + ":" + cLibraryFName
  998.                 SET LIBRARY TO (cLibrary) ADDITIVE
  999.                 THIS.SetErrorOff = .f.
  1000.                 IF THIS.HadError
  1001.                     THIS.Alert(cBadLibMessage + ".")
  1002.                     RETURN ""
  1003.                 ENDIF
  1004.                 IF PARAMETERS() > 2
  1005.                     IF &cVersionFuncName() < cReqVersion
  1006.                         RELEASE LIBRARY (cLibrary)
  1007.                         THIS.Alert(cBadVersMessage + cLibraryFName)
  1008.                         RETURN ""
  1009.                     ENDIF
  1010.                 ENDIF
  1011.  
  1012.             CASE ADIR(aFile, SYS(2004) + cLibraryFName) = 1
  1013.                 *- look in Foxpro startup folder
  1014.                 THIS.SetErrorOff = .t.
  1015.                 cLibrary = SYS(2004) + cLibraryFName
  1016.                 SET LIBRARY TO (SYS(2004) + cLibraryFName) ADDITIVE
  1017.                 THIS.SetErrorOff = .f.
  1018.                 IF THIS.HadError
  1019.                     THIS.Alert(cBadLibMessage + ".")
  1020.                     RETURN ""
  1021.                 ENDIF
  1022.                 IF PARAMETERS() > 2
  1023.                     IF &cVersionFuncName() < cReqVersion
  1024.                         RELEASE LIBRARY (cLibrary)
  1025.                         THIS.Alert(cBadVersMessage)
  1026.                         RETURN ""
  1027.                     ENDIF
  1028.                 ENDIF
  1029.  
  1030.  
  1031.             OTHERWISE
  1032.                 THIS.Alert(cBadLibMessage + ".")
  1033.                     RETURN ""
  1034.  
  1035.         ENDCASE
  1036.  
  1037.         RETURN cLibrary
  1038.  
  1039.     ENDFUNC
  1040.  
  1041.     *----------------------------------
  1042.     FUNCTION LocateApp
  1043.     *----------------------------------
  1044.         PARAMETER cSig
  1045.  
  1046.         LOCAL ax
  1047.  
  1048.         *- NOTE: Mac version of Foxtools must be loaded!
  1049.         IF !("FOXTOOL" $ SET("LIBR"))
  1050.             RETURN ""
  1051.         ENDIF
  1052.  
  1053.         DIMENSION ax[4]
  1054.         ax = ""
  1055.         IF FxGetCreat(cSig,0,@ax) == 0
  1056.             RETURN ax[4] + ax[1]
  1057.         ELSE
  1058.             *- error
  1059.             RETURN ""
  1060.         ENDIF
  1061.  
  1062.     ENDFUNC
  1063.  
  1064.     *-
  1065.     *- next four functions (GetPref, PutPref, FindINI and GetINISection) support working
  1066.     *- with .INI type files on the Macintosh.
  1067.     *-
  1068.  
  1069.     #DEFINE C_CRLF        CHR(13) + CHR(10)
  1070.     #DEFINE C_CR        CHR(13)
  1071.  
  1072.     *----------------------------------
  1073.     FUNCTION PutPref
  1074.     *----------------------------------
  1075.         *- write value to an INI-style file
  1076.  
  1077.         PARAMETERS cSection, cItem, cNewValue, cINIFile
  1078.  
  1079.         LOCAL cFile, iSelect, iLine, iMemoWidth, cValue, iCtr, cUItem, ;
  1080.             lWritten, iPrev, cOldSafety
  1081.  
  1082.         lWritten = .F.
  1083.  
  1084.         *- see if INI file is there
  1085.         *- first look for value that was passed
  1086.         cFile = THIS.FindINI(m.cINIFile)
  1087.         IF EMPTY(cFile)
  1088.             *- gave up
  1089.             RETURN
  1090.         ENDIF
  1091.         
  1092.         *- assume found, load into memo file
  1093.         iSelect = SELECT()
  1094.         CREATE CURSOR _temp (content m)
  1095.         APPEND BLANK
  1096.         APPEND MEMO content FROM (m.cFile)
  1097.  
  1098.         iMemoWidth = SET("MEMOWIDTH")
  1099.         SET MEMOWIDTH TO 254
  1100.  
  1101.         cValue = ""
  1102.         iLine = ATCLINE("["+ cSection + "]", content)
  1103.         IF iLine > 0
  1104.             _MLINE = 0
  1105.             iLenItem = LEN(m.cItem)
  1106.             cUItem = UPPER(m.cItem)
  1107.             cLine = MLINE(_temp.content, m.iLine)
  1108.             iPrev = _MLINE
  1109.             cLine = MLINE(_temp.content, 1, _MLINE)
  1110.             FOR iCtr = 1 TO MEMLINES(_temp.content) - iLine 
  1111.                 IF LEFT(cLine,1) == "[" OR EMPTY(ALLT(cLine))
  1112.                     EXIT
  1113.                 ENDIF
  1114.                 IF UPPER(LEFT(cLine,iLenItem)) == m.cUItem
  1115.                     *- found the line
  1116.                     IF "=" $ m.cLine
  1117.                         REPLACE content WITH LEFT(_temp.content, m.iPrev) + cItem + ;
  1118.                             "=" + cNewValue + ;
  1119.                             SUBS(_temp.content, m.iPrev + LEN(cLine) + ;
  1120.                             IIF(SUBS(_temp.content,iPrev,1) $ C_CRLF,1,0) + ;
  1121.                             IIF(SUBS(_temp.content,iPrev + 1,1) $ C_CRLF,1,0))
  1122.                         lWritten = .T.
  1123.                         EXIT
  1124.                     ENDIF
  1125.                 ENDIF
  1126.                 iPrev = _MLINE
  1127.                 cLine = MLINE(_temp.content, 1, _MLINE)
  1128.             NEXT
  1129.  
  1130.             IF !lWritten
  1131.                 *- must have hit a new section in file, or eof
  1132.                 REPLACE content WITH LEFT(_temp.content,m.iPrev) + cItem + ;
  1133.                     "=" + cNewValue + ;
  1134.                     SUBS(_temp.content, m.iPrev)
  1135.                 lWritten = .T.
  1136.             ENDIF
  1137.  
  1138.         ENDIF
  1139.  
  1140.         IF !lWritten
  1141.             *- must be no section by that name, so add it
  1142.             REPLACE content WITH _temp.content + CHR(13) + ;
  1143.                 "[" + m.cSection + "]" + CHR(13) + ;
  1144.                 cItem + "=" + cNewValue + CHR(13)
  1145.             lWritten = .T.
  1146.         ENDIF
  1147.  
  1148.         IF lWritten
  1149.             *- write out the revised file
  1150.             cOldSafety = SET('SAFETY')
  1151.             SET SAFETY OFF
  1152.             COPY MEMO content TO (cFile + '.')
  1153.             SET SAFETY &cOldSafety
  1154.         ENDIF
  1155.  
  1156.         SET MEMOWIDTH TO iMemoWidth
  1157.         USE IN _temp
  1158.         SELECT (iSelect)
  1159.  
  1160.     ENDFUNC
  1161.  
  1162.     *----------------------------------
  1163.     FUNCTION GetPref
  1164.     *----------------------------------
  1165.         *- read values from an INI-style file
  1166.         *- returns value
  1167.  
  1168.         PARAMETERS cSection, cItem, cINIFile
  1169.  
  1170.         LOCAL cFile, iSelect, iLine, iMemoWidth, cValue, iCtr, iFH
  1171.  
  1172.         cValue = ""
  1173.         cFile = THIS.FindINI(m.cINIFile)
  1174.         IF EMPTY(cFile)
  1175.             *- gave up
  1176.             RETURN ""
  1177.         ENDIF
  1178.  
  1179.         iFH = FOPEN(cFile)
  1180.         IF iFH == -1
  1181.             *- couldn't open the file for some reason
  1182.             RETURN ""
  1183.         ENDIF
  1184.  
  1185.         iLenItem = LEN(m.cItem)
  1186.         cItem = UPPER(cItem)
  1187.  
  1188.         DO WHILE !FEOF(m.iFH)
  1189.             cLine = FGETS(m.iFH)
  1190.             IF ATC("["+ cSection + "]", LTRIM(cLine)) == 1
  1191.                 *- found the section
  1192.                 DO WHILE !FEOF(m.iFH)
  1193.                     cLine = FGETS(m.iFH)
  1194.                     IF LEFT(cLine,1) == "[" OR EMPTY(ALLT(cLine))
  1195.                         *- new section -- must have failed
  1196.                         EXIT
  1197.                     ENDIF
  1198.                     IF UPPER(LEFT(cLine,iLenItem)) == m.cItem AND "=" $ m.cLine
  1199.                         *- found the line
  1200.                         cValue = SUBS(m.cLine,AT("=",m.cLine) + 1)
  1201.                         EXIT
  1202.                     ENDIF
  1203.                 ENDDO    && within section
  1204.             ENDIF        && found the section header
  1205.         ENDDO            && going through entire file
  1206.  
  1207.         =FCLOSE(m.iFH)
  1208.  
  1209.         RETURN m.cValue
  1210.  
  1211.     ENDFUNC
  1212.  
  1213.     *----------------------------------
  1214.     FUNCTION FindINI
  1215.     *----------------------------------
  1216.         *- hunt for a file -- look first in current folder, then home() folder
  1217.         *- then in system preferences folder
  1218.  
  1219.         PARAMETER cINIFile
  1220.         LOCAL cFile
  1221.         cFile = m.cINIFile
  1222.         IF !FILE(m.cFile)
  1223.             *- then look in FoxPro home folder
  1224.             cFile = HOME() + m.cINIFile
  1225.             IF !FILE(m.cFile)
  1226.                 *- then look in preferences file
  1227.                 cFile = SYS(2033,2) + ":" + m.cINIFile
  1228.                 IF !FILE(m.cFile)
  1229.                     *- give up
  1230.                     RETURN ""
  1231.                 ENDIF
  1232.             ENDIF
  1233.         ENDIF
  1234.         RETURN cFile
  1235.     ENDFUNC
  1236.  
  1237.     *----------------------------------
  1238.     FUNCTION GetINISection
  1239.     *----------------------------------
  1240.         *- populate an array with all items within a given section
  1241.         PARAMETERS aSections, cSection, cINIFile
  1242.  
  1243.         EXTERNAL ARRAY aSections
  1244.  
  1245.         LOCAL lDone
  1246.  
  1247.         #DEFINE ERROR_SUCCESS        0        && OK
  1248.         #DEFINE ERROR_NOINIFILE        -108    && DLL file to check INI not found
  1249.         #DEFINE ERROR_NOINIENTRY    -109    && No entry in INI file
  1250.         #DEFINE ERROR_FAILINI        -110    && failed to get INI entry
  1251.  
  1252.  
  1253.         cFile = THIS.FindINI(m.cINIFile)
  1254.         IF EMPTY(cFile)
  1255.             *- gave up
  1256.             RETURN ERROR_NOINIFILE
  1257.         ENDIF
  1258.  
  1259.         iFH = FOPEN(cFile)
  1260.         IF iFH == -1
  1261.             *- couldn't open the file for some reason
  1262.             RETURN ERROR_FAILINI
  1263.         ENDIF
  1264.  
  1265.         m.lDone = .F.
  1266.  
  1267.         DO WHILE !lDone
  1268.             cLine = FGETS(m.iFH)
  1269.             IF FEOF(m.iFH)
  1270.                 m.lDone = .T.
  1271.                 EXIT
  1272.             ENDIF
  1273.             IF ATC("["+ cSection + "]", LTRIM(cLine)) == 1
  1274.                 *- found the section
  1275.                 DO WHILE !FEOF(m.iFH)
  1276.                     cLine = FGETS(m.iFH)
  1277.                     IF LEFT(cLine,1) == "[" OR EMPTY(ALLT(cLine))
  1278.                         *- new section
  1279.                         m.lDone = .T.
  1280.                         EXIT
  1281.                     ENDIF
  1282.                     *- insert item into array
  1283.                     THIS.InsaItem(@aSections,ALLT(LEFT(cLine,AT("=",m.cLine) - 1)))
  1284.                 ENDDO    && within section
  1285.             ENDIF        && found the section header
  1286.         ENDDO            && going through entire file
  1287.  
  1288.         =FCLOSE(m.iFH)
  1289.  
  1290.         RETURN IIF(EMPTY(aSections[1]), ERROR_NOINIENTRY, ERROR_SUCCESS)
  1291.  
  1292.     ENDFUNC
  1293.  
  1294.     *----------------------------------
  1295.     FUNCTION FxStripLF
  1296.     *----------------------------------
  1297.         *- strip line feeds from file
  1298.         PARAMETER cFile
  1299.  
  1300.         LOCAL iFH, cBuffer, iSelect
  1301.  
  1302.         *- NOTE: If Foxtools is loaded, use it
  1303.         IF !("FOXTOOL" $ SET("LIBR"))
  1304.             =FxStripLF(cFile)
  1305.             RETURN
  1306.         ENDIF
  1307.  
  1308.         iSelect = SELECT()
  1309.  
  1310.         IF !FILE(cFILE)
  1311.             RETURN
  1312.         ENDIF
  1313.  
  1314.         CREATE CURSOR _temp1 (cText m)
  1315.         APPEND BLANK
  1316.         APPEND MEMO cText FROM (cFile)
  1317.         REPLACE cText WITH CHRTRAN(cText,C_CRLF,C_CR)
  1318.         COPY MEMO cText TO (cFile)
  1319.         IF JustStem(cFile) == JustFName(cfile)
  1320.             *- there was no extension, and COPY MEMO will have added one...
  1321.             IF FILE(cFile + '.TXT')
  1322.                 ERASE (cFile)
  1323.                 RENAME (cFile + '.TXT') TO (cFile)
  1324.             ENDIF
  1325.         ENDIF
  1326.         USE IN _temp1
  1327.         SELECT (iSelect)
  1328.  
  1329.         RETURN
  1330.     ENDFUNC
  1331.     
  1332. #ENDIF
  1333.  
  1334. ENDDEFINE
  1335.         
  1336. ******************************************************************************
  1337. DEFINE CLASS WizEngineAll AS WizEngine 
  1338. ******************************************************************************
  1339.     procedure IsWizEngineAll
  1340.         * This function is used by WizLocFile to determine whether the engine
  1341.         * is based on WizEngineAll.
  1342.         return .t.
  1343.     endproc
  1344.     
  1345.     procedure aScanner
  1346.         * This procedure searches an array for an expression and returns 
  1347.         * the element number of the first match. (Pass .T. for lReturnRow to
  1348.         * get the Row number.)
  1349.         * The search may be restricted to a particular column of the array.
  1350.         * This procedure makes a copy of the array received to allow it to work
  1351.         * with member arrays.
  1352.         
  1353.         parameters m.cArrayName, m.expression, m.column, m.lReturnRow, ;
  1354.             m.start, m.howmany
  1355.             
  1356.         private lSingleDimension, iElement, thearray
  1357.         
  1358.         =acopy(&cArrayName, thearray)
  1359.         
  1360.         if alen(thearray,2)=0
  1361.             dimension thearray[alen(thearray),1]
  1362.             m.lSingleDimension=.t.
  1363.         else
  1364.             m.lSingleDimension=.f.
  1365.         endif
  1366.         m.iElement=iif(type('m.start')='N',m.start-1,0)
  1367.         m.column=iif(empty(m.column),1,m.column)
  1368.         m.start=iif(empty(m.start),1,m.start)
  1369.         m.howmany=iif(empty(m.howmany),alen(thearray),m.howmany)
  1370.         do while .t.
  1371.             m.iElement=ascan(thearray,expression,m.iElement+1,m.howmany)
  1372.             if m.iElement=0 .or. asubscript(thearray,m.iElement,2)=m.column
  1373.                 exit
  1374.             else
  1375.                 m.howmany=m.howmany-m.iElement
  1376.             endif
  1377.         enddo
  1378.         if m.lSingleDimension
  1379.             dimension thearray[alen(thearray,1)]
  1380.         endif
  1381.         return iif(m.lReturnRow, ;
  1382.             iif(m.iElement = 0, 0, asubscript(thearray, m.iElement, 1)), m.iElement)
  1383.     endproc
  1384.  
  1385.     PROCEDURE insaitem
  1386.         * Inserts an array element into an array.
  1387.         * For 1-D array
  1388.         LPARAMETER aArray,sContents,iRow
  1389.         IF ALEN(aArray) = 1 AND EMPTY(aArray[1])
  1390.           aArray[1]=m.sContents
  1391.         ELSE
  1392.           DIMENSION aArray[ALEN(aArray)+1,1]
  1393.           IF PARAM()=2
  1394.             aArray[ALEN(aArray)]=m.sContents
  1395.           ELSE
  1396.             =AINS(aArray,m.iRow+1)
  1397.             aArray[m.iRow+1]=m.sContents
  1398.           ENDIF    
  1399.         ENDIF
  1400.     ENDPROC
  1401.     
  1402.     PROCEDURE delaitem
  1403.         * Generic routine to delete an array element.
  1404.         LPARAMETERS aArray,wziRow
  1405.         IF ALEN(aArray)>=m.wziRow
  1406.           IF ALEN(aArray)=1
  1407.             aArray=''
  1408.           ELSE
  1409.             =ADEL(aArray,m.wziRow)
  1410.             DIMENSION aArray[ALEN(aArray)-1]
  1411.           ENDIF
  1412.         ENDIF
  1413.     ENDPROC
  1414.  
  1415.     FUNCTION acolscan
  1416.         * This function does an ASCAN for a specific row where
  1417.         * aSearch - array to scan
  1418.         * sExpr - expression to scan
  1419.         * nColumn - column to scan
  1420.         * lRetRow - return row (T) or array element (F)
  1421.         LPARAMETER aSearch,sExpr,nColumn,lRetRow
  1422.         LOCAL apos
  1423.         IF TYPE('m.nColumn')#'N'
  1424.             nColumn =1
  1425.         ENDIF
  1426.         IF TYPE('m.lRetRow')#'L'
  1427.             m.RetRow = .F.
  1428.         ENDIF
  1429.         
  1430.         m.apos = 1
  1431.         DO WHILE .T.
  1432.             m.apos = ASCAN(aSearch,m.sExpr,m.apos)
  1433.             DO CASE
  1434.             CASE m.apos=0    && did not find match
  1435.                 EXIT
  1436.             CASE ASUBSCRIPT(aSearch,m.apos,2)=m.nColumn
  1437.                 EXIT
  1438.             OTHERWISE
  1439.                 m.apos=m.apos+1
  1440.             ENDCASE
  1441.         ENDDO
  1442.         IF m.lRetRow AND m.aPos > 0
  1443.             RETURN ASUBSCRIPT(aSearch,m.apos,1)
  1444.         ELSE
  1445.             RETURN m.apos
  1446.         ENDIF
  1447.     ENDPROC
  1448.  
  1449.     PROCEDURE SaveOutFile
  1450.         LPARAMETER pMess,pDefFile,pExtn
  1451.         LOCAL cSaveFile,wziFHand
  1452.     
  1453.         IF TYPE("m.pMess")# "C"
  1454.             m.pMess = ""
  1455.         ENDIF
  1456.         IF TYPE("m.pDefFile")# "C"
  1457.             m.pDefFile = ""
  1458.         ENDIF
  1459.         IF TYPE("m.pExtn")# "C" OR EMPTY(m.pExtn)
  1460.             m.pExtn = "*"
  1461.         ENDIF
  1462.     
  1463.         DO WHILE .T.
  1464.             m.cSaveFile = PUTFILE(m.pMess,m.pDefFile,m.pExtn)
  1465.         
  1466.             IF EMPTY(m.cSaveFile)
  1467.                 EXIT
  1468.             ENDIF
  1469.         
  1470.             IF m.pExtn # "*"
  1471.                 m.cSaveFile = THIS.FORCEEXT(m.cSaveFile,m.pExtn)
  1472.             ENDIF
  1473.         
  1474.             IF FILE(m.cSaveFile)
  1475.                 *check if file already open
  1476.                 m.wziFHand=FOPEN(m.cSaveFile)
  1477.                 IF m.wziFHand= -1
  1478.                     THIS.Alert(C_FILEUSE2_LOC)
  1479.                     LOOP
  1480.                 ENDIF
  1481.                 =FCLOSE(m.wziFHand)
  1482.             ENDIF
  1483.             
  1484.             EXIT
  1485.         ENDDO
  1486.         
  1487.         THIS.cOutFile = m.cSaveFile
  1488.         RETURN !EMPTY(THIS.cOutFile)
  1489.     ENDPROC
  1490.  
  1491.     FUNCTION JustPath
  1492.         * Returns just the pathname.
  1493.         LPARAMETERS m.filname
  1494.         LOCAL cdirsep
  1495.         cdirsep = IIF(_mac,':','\')
  1496.         m.filname = SYS(2027,ALLTRIM(UPPER(m.filname)))
  1497.         IF m.cdirsep $ m.filname
  1498.            m.filname = SUBSTR(m.filname,1,RAT(m.cdirsep,m.filname))
  1499.            IF RIGHT(m.filname,1) = m.cdirsep AND LEN(m.filname) > 1 ;
  1500.                     AND SUBSTR(m.filname,LEN(m.filname)-1,1) <> ':'
  1501.                  filname = SUBSTR(m.filname,1,LEN(m.filname)-1)
  1502.            ENDIF
  1503.            RETURN m.filname
  1504.         ELSE
  1505.            RETURN ''
  1506.         ENDIF
  1507.     ENDFUNC
  1508.     
  1509.     FUNCTION ForceExt
  1510.         * Force filename to have a particular extension.
  1511.         LPARAMETERS m.filname,m.ext
  1512.         LOCAL m.ext
  1513.         IF SUBSTR(m.ext,1,1) = "."
  1514.            m.ext = SUBSTR(m.ext,2,3)
  1515.         ENDIF
  1516.  
  1517.         m.pname = THIS.justpath(m.filname)
  1518.         m.filname = THIS.justfname(UPPER(ALLTRIM(m.filname)))
  1519.         IF AT('.',m.filname) > 0
  1520.            m.filname = SUBSTR(m.filname,1,AT('.',m.filname)-1) + '.' + m.ext
  1521.         ELSE
  1522.            m.filname = m.filname + '.' + m.ext
  1523.         ENDIF
  1524.         RETURN THIS.addbs(m.pname) + m.filname
  1525.     ENDFUNC
  1526.     
  1527.     FUNCTION JustFname
  1528.         * Return just the filename (i.e., no path) from "filname"
  1529.         LPARAMETERS m.filname
  1530.         LOCAL clocalfname, cdirsep
  1531.         clocalfname = SYS(2027,m.filname)
  1532.         cdirsep = IIF(_mac,':','\')
  1533.         IF RAT(m.cdirsep ,m.clocalfname) > 0
  1534.            m.clocalfname= SUBSTR(m.clocalfname,RAT(m.cdirsep,m.clocalfname)+1,255)
  1535.         ENDIF
  1536.         IF AT(':',m.clocalfname) > 0
  1537.            m.clocalfname= SUBSTR(m.clocalfname,AT(':',m.clocalfname)+1,255)
  1538.         ENDIF
  1539.         RETURN ALLTRIM(UPPER(m.clocalfname))
  1540.     ENDFUNC
  1541.  
  1542.     FUNCTION AddBS
  1543.         * Add a backslash unless there is one already there.
  1544.         LPARAMETER m.pathname
  1545.         LOCAL m.separator
  1546.         m.separator = IIF(_MAC,":","\")
  1547.         m.pathname = ALLTRIM(UPPER(m.pathname))
  1548.         IF !(RIGHT(m.pathname,1) $ '\:') AND !EMPTY(m.pathname)
  1549.            m.pathname = m.pathname + m.separator
  1550.         ENDIF
  1551.         RETURN m.pathname
  1552.     ENDFUNC
  1553.  
  1554.     FUNCTION JustStem
  1555.         * Return just the stem name from "filname"
  1556.         LPARAMETERS m.filname
  1557.         IF RAT('\',m.filname) > 0
  1558.            m.filname = SUBSTR(m.filname,RAT('\',m.filname)+1,255)
  1559.         ENDIF
  1560.         IF RAT(':',m.filname) > 0
  1561.            m.filname = SUBSTR(m.filname,RAT(':',m.filname)+1,255)
  1562.         ENDIF
  1563.         IF AT('.',m.filname) > 0
  1564.            m.filname = SUBSTR(m.filname,1,AT('.',m.filname)-1)
  1565.         ENDIF
  1566.         RETURN ALLTRIM(UPPER(m.filname))
  1567.     ENDFUNC
  1568.  
  1569.     FUNCTION justext
  1570.         * Return just the extension from "filname"
  1571.         PARAMETERS m.filname
  1572.         LOCAL m.ext
  1573.         m.filname = this.justfname(m.filname)   && prevents problems with ..\ paths
  1574.         m.ext = ""
  1575.         IF AT('.', m.filname) > 0
  1576.            m.ext = SUBSTR(m.filname, AT('.', m.filname) + 1, 3)
  1577.         ENDIF
  1578.         RETURN UPPER(m.ext)
  1579.     ENDFUNC
  1580.     
  1581.     FUNCTION GetStyle
  1582.         PARAMETER lIsBold,lIsItalic,lIsUnder
  1583.         DO CASE
  1584.         CASE m.lIsBold AND m.lIsItalic AND m.lIsUnder
  1585.             RETURN "BIU"
  1586.         CASE m.lIsBold AND m.lIsItalic 
  1587.             RETURN "BI"
  1588.         CASE m.lIsBold AND m.lIsUnder
  1589.             RETURN "BU"
  1590.         CASE m.lIsItalic AND m.lIsUnder
  1591.             RETURN "IU"
  1592.         CASE m.lIsBold 
  1593.             RETURN "B"
  1594.         CASE m.lIsItalic 
  1595.             RETURN "I"
  1596.         CASE m.lIsUnder
  1597.             RETURN "U"
  1598.         OTHERWISE
  1599.             RETURN "N"
  1600.         ENDCASE
  1601.     ENDFUNC
  1602.  
  1603.     PROCEDURE AddCdxTag
  1604.         * Takes contents from THIS.aWizSorts array and creates an index TAG
  1605.         * from the fields passed in array. If an expression already exists
  1606.         * no tag is made and the tag name is returned.
  1607.         * Assume database is already selected since a new index TAG is created.
  1608.         * Parameters:
  1609.         *   aSrtArray - reference of sort fields array (e.g., aSortFields)
  1610.         *   aFieldsRef - reference of instance array (e.g., aWizFList, aGridFList)
  1611.         
  1612.         PARAMETER aSortRef,aFieldsRef
  1613.         
  1614.         IF PARAMETER() # 2
  1615.             THIS.ALERT(C_BADPARMS_LOC)
  1616.             RETURN ""
  1617.         ENDIF
  1618.         
  1619.         PRIVATE aSorts
  1620.         DIMENSION aSorts[1,1]
  1621.         STORE "" TO aSorts
  1622.         =ACOPY(THIS.&aSortRef.,aSorts)        
  1623.         
  1624.         PRIVATE sTagName,sFldExpr,sTagExpr,lHasmemo,sCurAlias,cSortFld
  1625.         PRIVATE sCdxName,i,sDBF,wzaCDX,aFileInfo,nTmpCnt,cTmpName,nbuffering
  1626.         STORE '' TO sFldExpr,sTagExpr,sTagName,cTmpName,iPos 
  1627.         STORE 1 TO nTmpCnt
  1628.         
  1629.         * Nothing to sort
  1630.         IF EMPTY(aSorts[1,1])
  1631.           RETURN ''
  1632.         ENDIF
  1633.  
  1634.         * Check if cursor in use
  1635.         IF AT('.TMP',DBF()) # 0
  1636.           RETURN ''
  1637.         ENDIF
  1638.  
  1639.         * Also check if read-only
  1640.         =ADIR(aFileInfo,DBF())
  1641.         IF AT('R',aFileInfo[5])#0
  1642.             RETURN ''
  1643.         ENDIF
  1644.         RELEASE aFileInfo
  1645.  
  1646.         m.sCurAlias=ALIAS()                            && alias name
  1647.         m.sDBF = DBF()                                && DBF stem
  1648.         m.sCdxName = THIS.FORCEEXT(m.sDBF,'CDX')     && CDX name
  1649.  
  1650.         * make sure we have variable defined
  1651.         IF TYPE('THIS.lSortAscend')#'L'
  1652.             THIS.lSortAscend = .T.
  1653.         ENDIF
  1654.  
  1655.         * Get index expression here
  1656.         = ACOPY(aSorts,wzaCdx)
  1657.         STORE .F. TO wzaCdx
  1658.  
  1659.         * Get tag expression looping through fields and type casting
  1660.         * for different data types on fields.
  1661.         FOR i = 1 TO ALEN(aSorts)
  1662.  
  1663.             FOR iPos = 1 TO ALEN(THIS.&aFieldsRef.,1)
  1664.               IF UPPER(THIS.&aFieldsRef.[m.iPos,1])==UPPER(aSorts[m.i])
  1665.                 EXIT
  1666.               ENDIF
  1667.             ENDFOR
  1668.             
  1669.             m.cSortFld = THIS.&aFieldsRef.[m.iPos,1]
  1670.             
  1671.             * check if alias used
  1672.             IF AT('.',m.cSortFld) # 0
  1673.                 m.cSortFld = SUBSTR(m.cSortFld,AT('.',m.cSortFld)+1)
  1674.             ENDIF
  1675.             
  1676.             m.sFldExpr = THIS.GetTagExpr(m.cSortFld,THIS.&aFieldsRef.[m.iPos,2],THIS.&aFieldsRef.[m.iPos,3],THIS.&aFieldsRef.[m.iPos,4],(ALEN(aSorts)=1))
  1677.  
  1678.             IF !EMPTY(m.sFldExpr)
  1679.                 m.sTagExpr = m.sTagExpr + IIF(EMPTY(m.sTagExpr),"","+") + m.sFldExpr
  1680.             ENDIF
  1681.           
  1682.         ENDFOR
  1683.         
  1684.         * Get CDX Tag name - use WIZARD_1, WIZARD_2, etc. if expression
  1685.         IF ALEN(aSorts) = 1
  1686.             m.sTagName = LEFT(aSorts[1],10)
  1687.         ELSE
  1688.             m.sTagName = "WIZARD_1"
  1689.         ENDIF
  1690.  
  1691.         * Check for unique Tag name
  1692.         DO WHILE TAGNO(m.sTagName)#0
  1693.             nTmpCnt = nTmpCnt + 1
  1694.             m.sTagName = "WIZARD_"+ALLTRIM(STR(nTmpCnt))
  1695.         ENDDO
  1696.         
  1697.         * Create new index tag here
  1698.         m.wzhaderr = .F.
  1699.         m.wzisexcl = .T.
  1700.  
  1701.         * check if file can be locked, else try to open it exclusively
  1702.         IF !ISFLOCKED()
  1703.             m.wzisexcl=.F.
  1704.             *- set up for error handling
  1705.             THIS.SetErrorOff = .T.
  1706.             USE (m.sDBF) AGAIN ALIAS (m.sCurAlias) EXCLUSIVE
  1707.             IF EMPTY(ALIAS()) OR !ISEXCLUSIVE()    && file in use error -- could not open exclusive
  1708.               m.sTagName=""
  1709.               m.wzhaderr=.T.
  1710.             ENDIF
  1711.             THIS.SetErrorOff = .F.
  1712.         ENDIF
  1713.  
  1714.         m.wzstagdesc=IIF(THIS.lSortAscend,'',' DESC')
  1715.         
  1716.         * create tag since we now have dbf exclusive
  1717.         IF !m.wzhaderr
  1718.           m.nbuffering = cursorgetprop('buffering')
  1719.           * Check if a tag already exists with same expression
  1720.           IF FILE(m.sCdxName)
  1721.             FOR m.i = 1 TO 256            && max # of tags
  1722.               IF EMPTY(TAG(m.sCdxName,m.i))
  1723.                 IF m.nbuffering > 3        && tablebuffering
  1724.                     =TABLEUPDATE(.T.,.T.)
  1725.                     =cursorsetprop('buffering',1)
  1726.                 ENDIF
  1727.                 INDEX ON &sTagExpr TAG &sTagName &wzstagdesc
  1728.                 EXIT
  1729.               ENDIF
  1730.               * found tag with same expr (checks for asce/desc)
  1731.               * use NORMALIZE function to ensure that functions are not abbrev
  1732.               IF UPPER(NORM(KEY(m.sCdxName,m.i)))=UPPER(NORM(m.sTagExpr))
  1733.                    wzsTmpTag=TAG(m.sCdxName,m.i)
  1734.                 SET ORDER TO &wzsTmpTag
  1735.                 IF (!THIS.lSortAscend AND 'DESCENDING'$SET('ORDER')) OR ;
  1736.                    (THIS.lSortAscend AND !'DESCENDING'$SET('ORDER'))
  1737.                     sTagName=TAG(m.sCdxName,m.i)
  1738.                     EXIT
  1739.                 ENDIF
  1740.               ENDIF
  1741.             ENDFOR
  1742.           ELSE
  1743.             IF m.nbuffering > 3        && tablebuffering
  1744.                 =TABLEUPDATE(.T.,.T.)
  1745.                 =cursorsetprop('buffering',1)
  1746.             ENDIF
  1747.             INDEX ON &sTagExpr TAG &sTagName &wzstagdesc
  1748.           ENDIF
  1749.           IF m.nbuffering > 3        && tablebuffering
  1750.               =cursorsetprop('buffering',m.nbuffering)
  1751.           ENDIF
  1752.         ENDIF
  1753.  
  1754.         DO CASE
  1755.         CASE m.wzhaderr        && an error occured so reset original
  1756.             USE (m.sDBF) AGAIN ALIAS (m.sCurAlias) SHARED
  1757.         CASE !m.wzisexcl    && need to restore to original
  1758.             USE (m.sDBF) AGAIN ALIAS (m.sCurAlias) SHARED ORDER &sTagName
  1759.         OTHERWISE
  1760.             * already indexed -- do nothing
  1761.         ENDCASE
  1762.  
  1763.         LOCATE    && goto top
  1764.         RETURN m.sTagName
  1765.  
  1766.     ENDPROC
  1767.  
  1768.     PROCEDURE GetTagExpr
  1769.         * Routine returns character expression for sort field
  1770.         * so that a compound index can be made.
  1771.  
  1772.         LPARAMETER sortfld,cDataType,nDataWid,nDataDec,lOneField
  1773.  
  1774.         DO CASE
  1775.           CASE m.cDataType = DT_CHAR AND m.nDataWid>40
  1776.               * Note: since we allow 3 fields for sorting and Maximum Key 
  1777.               * length per expression is 120 (for intl collate), 
  1778.               * set limit to 40 per field.
  1779.             RETURN "LEFT("+m.sortfld+",40)"
  1780.           CASE m.cDataType = DT_CHAR
  1781.             RETURN m.sortfld
  1782.           CASE INLIST(m.cDataType,DT_NUM,DT_FLOAT,DT_INTEGER,DT_DOUBLE,DT_CURRENCY) AND m.lOneField
  1783.             RETURN m.sortfld
  1784.           CASE m.cDataType = DT_LOGIC
  1785.             RETURN "IIF("+m.sortfld+",'T','F')"
  1786.           CASE m.cDataType = DT_INTEGER
  1787.             RETURN "STR("+m.sortfld+")"
  1788.           CASE INLIST(m.cDataType,DT_NUM,DT_FLOAT)
  1789.             RETURN "STR("+m.sortfld+","+ALLT(STR(m.nDataWid))+;
  1790.                 ","+ALLT(STR(m.nDataDec))+")"
  1791.           CASE m.cDataType = DT_CURRENCY
  1792.             RETURN "ALLT(STR("+m.sortfld+",16,4))"
  1793.           CASE m.cDataType = DT_DOUBLE
  1794.             RETURN "ALLT(STR(SIGN("+m.sortfld+")*IIF("+m.sortfld+"=0,0,LOG10(ABS("+m.sortfld+"))),20,16))"
  1795.           CASE m.cDataType = DT_DATE
  1796.             RETURN "DTOS("+m.sortfld+")"
  1797.           CASE m.cDataType = DT_DATETIME
  1798.              RETURN "DTOS(TTOD("+m.sortfld+"))+STR(HOUR("+m.sortfld+;
  1799.              "),2)+STR(MINUTE("+m.sortfld+"),2)+STR(SEC("+m.sortfld+"),2)"
  1800.           OTHERWISE      && don't index
  1801.             RETURN ""
  1802.         ENDCASE
  1803.     ENDPROC
  1804.  
  1805.     PROCEDURE GetFullTagExpr
  1806.         * Get tag expression looping through fields and type casting
  1807.         * for different data types on fields.
  1808.         * This method assumes that DBF is already selected!!!
  1809.         
  1810.         LPARAMETER aSortArray
  1811.         LOCAL aFldData,i,ipos,sFldExpr,sTagExpr
  1812.         IF EMPTY(aSortArray[1])
  1813.             RETURN ""
  1814.         ENDIF
  1815.         DIMENSION aFldData[1]
  1816.         =AFIELDS(aFldData)
  1817.         sTagExpr = ""
  1818.         FOR i = 1 TO ALEN(aSortArray)
  1819.  
  1820.             IF EMPTY(aSortArray[m.i])
  1821.                 LOOP
  1822.             ENDIF
  1823.             
  1824.             FOR iPos = 1 TO ALEN(aFldData,1)
  1825.               IF UPPER(aFldData[m.iPos,1])==UPPER(aSortArray[m.i])
  1826.                 EXIT
  1827.               ENDIF
  1828.             ENDFOR
  1829.             
  1830.             sFldExpr = THIS.GetTagExpr(aSortArray[m.i],aFldData[m.iPos,2],aFldData[m.iPos,3],aFldData[m.iPos,4],(ALEN(aSortArray)=1))
  1831.  
  1832.             IF !EMPTY(m.sFldExpr)
  1833.                 sTagExpr = m.sTagExpr + IIF(EMPTY(m.sTagExpr),"","+") + m.sFldExpr
  1834.             ENDIF
  1835.         ENDFOR 
  1836.         RETURN sTagExpr 
  1837.     ENDPROC
  1838.         
  1839.     PROCEDURE GetDbcAlias
  1840.         * Takes the current DBC and gets its alias name
  1841.         * cDBC - DBC name passed if not current DBC()
  1842.  
  1843.         LPARAMETER cDBC
  1844.  
  1845.         LOCAL aDBCtmp,cGetDBC,nPos
  1846.  
  1847.         IF TYPE("m.cDBC") # "C"
  1848.             m.cDBC  =""
  1849.         ENDIF
  1850.  
  1851.         IF EMPTY(m.cDBC) AND EMPTY(DBC()) 
  1852.             RETURN ""
  1853.         ENDIF
  1854.  
  1855.         m.cGetDBC = IIF(EMPTY(m.cDBC),DBC(),UPPER(m.cDBC))
  1856.  
  1857.         DIMENSION aDBCtmp[1,2]
  1858.         =ADATA(aDBCtmp)
  1859.         m.nPos = ASCAN(aDBCtmp,m.cGetDBC)
  1860.  
  1861.         RETURN IIF(m.nPos = 0,"",aDBCtmp[m.nPos-1])
  1862.     ENDPROC
  1863.  
  1864.     PROCEDURE CheckDBCTag
  1865.         * Function returns .F. if DBC opened shared so unable to Index new tag
  1866.         * Assume that DBF is already selected when method called!
  1867.         
  1868.         LPARAMETER cSortExpr
  1869.         LOCAL cDBCAlias,cDBC,lIsView,cTagName,i
  1870.         cDBCAlias = ""
  1871.         lIsView = (CURSORGETPROP("SourceType") # 3)
  1872.         cDBC = CURSORGETPROP("DATABASE")
  1873.  
  1874.         IF m.lIsView OR EMPTY(m.cDBC)
  1875.             RETURN .T.
  1876.         ENDIF
  1877.  
  1878.         cDBCAlias = THIS.GetDbcAlias(m.cDBC)
  1879.         
  1880.         * Test for exclusive use of DBC
  1881.         IF !EMPTY(m.cDBCAlias) AND ISEXCLUSIVE(m.cDBCAlias,2)
  1882.             RETURN .T.
  1883.         ENDIF
  1884.  
  1885.         * DBC is opened shared, so test if tag exists
  1886.         * Scan for tag name, else create it
  1887.         cTagName = ""
  1888.         FOR i = 1 TO TagCount()
  1889.             IF UPPER(KEY(m.i)) == UPPER(m.cSortExpr)
  1890.                 cTagName = TAG(m.i)
  1891.                 EXIT
  1892.             ENDIF
  1893.         ENDFOR
  1894.  
  1895.         RETURN !EMPTY(m.cTagName)
  1896.     ENDPROC
  1897.  
  1898. ENDDEFINE
  1899.  
  1900.  
  1901. DEFINE CLASS AutoWiz AS custom
  1902.     
  1903.     *- Minimal Set if table/view already opened:
  1904.     *- Views need to be already opened because of issues with
  1905.     *- remote connections and parameterized views.
  1906.     lUsePages = .T.                    && use pages (form wizard)
  1907.     cWizTitle = ""                    && output document title
  1908.     cOutFile = ""                    && output file name
  1909.     nWizAction = 1                    && output action    (e.g., Save and modify)
  1910.     lSortAscend = .T.                && sort tag
  1911.     DIMENSION aWizFields[1,1]        && array of selected fields
  1912.     aWizFields = ""
  1913.     DIMENSION aWizSorts[1,1]        && array of sort fields
  1914.     aWizSorts = ""
  1915.     DIMENSION aWizStyles[2,2]        && array of style settings
  1916.     aWizStyle = ""
  1917.  
  1918.     *- No tables open
  1919.     cWizTable = ""                    && name of table to try and open
  1920.     cWizAlias = ""                    && alias to use    
  1921.  
  1922.     *- used by Reports
  1923.     lTruncate = .F.                    && don't wrap fields
  1924.     lLandscape = .F.                && portrait/landscape
  1925.     nColumns = 1                    && # of columns in report
  1926.     cStyleFile = ""                    && report style file
  1927.     nLayout = 1                        && report layout: 1 = columns, 2 = rows
  1928.  
  1929.     *- used by Labels
  1930.     DIMENSION aLblLines[1,1]        && contents of label lines
  1931.     lMetric = .F.                    && metric?
  1932.     lHasSortTag = .F.                && is sort field already a tag?
  1933.     cLblData = ""                    && label data
  1934.     
  1935. ENDDEFINE
  1936.  
  1937.  
  1938. #IF MAC_BUILD
  1939.  
  1940. *- a stub, to prevent build errors
  1941. *- this function is part of FoxTools for the Macintosh
  1942. PROCEDURE FxGetCreat
  1943. ENDPROC
  1944.  
  1945. #ENDIF
  1946.